/*
    获取access_token
        是什么？微信调用接口全局唯一凭据。
        特点：
            唯一的
            有效期为2小时，提前5分钟请求。
            接口权限，每天2000次。
            请求地址和方法：
            https请求方式: GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
    设计思路：
        1.首次本地没有，发送请求获取access_token，保存下来（本地文件）
        2.第二次或以后
            - 先去本地读取文件，判断是否过期
                -过期了
                    - 重新请求access_token，保存下来覆盖之前的文件（保证文件是唯一的）
                -  没过期直接使用
    整理思路
        读取文件(readAccessToken)
            -本地有文件
                判断是否过期(isValidAccessToken)
                    -过期了
                        - 重新请求access_token(getAccessToken)，保存下来覆盖之前的文件（保证文件是唯一的）(saveAccessToken)
                    -没过期
                        -直接使用   
            -本地没有文件
                发送请求获取access_token(getAccessToken)，保存下来（本地文件）(saveAccessToken),直接使用
*/
// 引入request请求
const rp = require('request-promise-native')
// 引入config文件
const {appID, appsecret} = require('../config')
const { json } = require('express')
const { resolve } = require('path')
const api = require('../utils/api')
const {writeFileAsync,readFileAsync} = require("../utils/tool")
class Wechat {
    constructor() {

    }
    /**
     * 用来获取access_token
     */
    getAccessToken() {
        // 定义请求地址
        const url = `${api.accessToken}&appid=${appID}&secret=${appsecret}`
        // 发送请求
        /**
         * 使用库，npm安装
         * request
         * request-promise-native 返回值promise对象
         */
        return new Promise((resolve,reject)=>{
            rp({method: 'GET',url,json:true})
            .then(res=>{
                console.log(res)
                //设置access_token的过期时间
                res.expires_in = Date.now() + (res.expires_in - 300) * 1000
                resolve(res)
            })
            .catch(err=>{
                reject('getAccessToken方法出了问题')
                console.log(err)
            })
        })
        
    }

    /**
     * 用来保存access_token
     * @param accessToken 要保存的凭据
     */
    saveAccessToken(accessToken) {
       return writeFileAsync(accessToken, './accessToken.text')
    }
    /**
     * 用来读取access_token
     */
    readAccessToken() {
       return readFileAsync('accessToken.text')
    }
    /**
     * 用来检测access_token的有效性
     * @param {*} data  
     */
    isValidAccessToken(data) {
        // 检测传入的参数是否是有效的
        if (!data && !data.access_token && !data.expires_in) {
            // flase代表access_token无效的
            return false
        }
        // 检测是否在有效期内
        // if(data.expires_in < Date.now()) {
        //     // 过期了true
        //     return false 
        // } else {
        //     return true
        // }
        return data.expires_in > Date.now()
    }
    /**
     * 用来获取没过期的access_token
     * @return {Promise<any>} access_token
     */
    fetchAccessToken() {
        if(this.access_token && this.expires_in && this.isValidAccessToken(this)) {
            return Promise.resolve({
                access_token: this.access_token,
                expires_in: this.expires_in
            })
        } 
        return this.readAccessToken().then(async res=>{
                let isValid = this.isValidAccessToken(res)
                if (isValid) {
                    return Promise.resolve(res)
                } else {
                    let res = await this.getAccessToken()
                    await this.saveAccessToken(res)
                    return Promise.resolve(res)
                }
            }).catch(async err=>{
                let res = await this.getAccessToken()
                await this.saveAccessToken(res)
                return Promise.resolve(res)
            }).then(res=>{
                this.access_token = res.access_token
                this.expires_in = res.expires_in
                return Promise.resolve(res)
            })

    }
    /**
     * 用来获取jsapi_ticket
     */
    getTicket() {
        
        // 发送请求
        /**
         * 使用库，npm安装
         * request
         * request-promise-native 返回值promise对象
         */
        return new Promise(async (resolve,reject)=>{
            // 获取access_token
            let data= await this.fetchAccessToken();
            // 定义请求地址
            const url = `${api.ticket}&access_token=${data.access_token}`
            rp({method: 'GET',url,json:true})
            .then(res=>{
                console.log(res)
                
                resolve({
                    ticket: res.ticket,
                    expires_in: Date.now() + (res.expires_in - 300) * 1000, //设置过期时间 

                })
            })
            .catch(err=>{
                reject('getJsapiTicket方法出了问题')
                console.log(err)
            })
        })
        
    }

    /**
     * 用来保存saveTicket
     * @param ticket 要保存的凭据
     */
    saveTicket(ticket) {
        return writeFileAsync(ticket, 'ticket.text')
    }
    /**
     * 用来读取readTicket
     */
    readTicket() {
        return readFileAsync('ticket.text')
    }
    /**
     * 用来检测access_token的有效性
     * @param {*} data  
     */
    isValidTicket(data) {
        // 检测传入的参数是否是有效的
        if (!data && !data.ticket && !data.ticket_expires_in) {
            // flase代表access_token无效的
            return false
        }
        // 检测是否在有效期内
        // if(data.expires_in < Date.now()) {
        //     // 过期了true
        //     return false 
        // } else {
        //     return true
        // }
        return data.expires_in > Date.now()
    }
    /**
     * 用来获取没过期的ticket
     * @return {Promise<any>} access_token
     */
    fetchTicket() {
        if(this.ticket && this.ticket_expires_in && this.isValidTicket(this)) {
            return Promise.resolve({
                ticket: this.ticket,
                expires_in: this.ticket_expires_in
            })
        } 
        return this.readTicket().then(async res=>{
                let isValid = this.isValidTicket(res)
                if (isValid) {
                    return Promise.resolve(res)
                } else {
                    let res = await this.getTicket()
                    await this.saveTicket(res)
                    return Promise.resolve(res)
                }
            }).catch(async err=>{
                let res = await this.getTicket()
                await this.saveTicket(res)
                return Promise.resolve(res)
            }).then(res=>{
                this.ticket = res.ticket
                this.ticket_expires_in = res.expires_in
                return Promise.resolve(res)
            })

    }
}
// (async ()=>{
//     const w = new Wechat();
//     const data = await w.fetchTicket();
//     console.log(data)
// })()

module.exports = Wechat